<template>
  <div class="layout-container">
    <el-card shadow="Never" class="card">
      <div class="header-container">
        <el-select v-model="selectedLanguage" @change="updateLanguage" class="select" size="default">
          <el-option
              v-for="option in options"
              :key="option.value"
              :label="option.label"
              :value="option.value">
          </el-option>
        </el-select>
        <div class="button-container">
          <el-button size="large" round class="run-button" @click="aiAnalysisCode">
            <img src="../../assets/aiCode.svg" alt="aiCode" class="button-icon">Ai分析
          </el-button>
          <template v-if="showInput">
            <el-input v-model="inputContent" placeholder="请输入内容" class="input-box"></el-input>
          </template>
          <template v-else>
            <el-button size="large" round @click="toggleInput">
              <img src="../../assets/input.svg" alt="Search" class="button-icon"> 输入
            </el-button>
          </template>
          <el-button size="large" round class="run-button" @click="executeCode">
            <img src="../../assets/start.svg" alt="Run" class="button-icon">运行
          </el-button>
        </div>
      </div>
      <el-divider/>
      <div ref="editContainer" class="code-editor"></div>
    </el-card>
    <el-card shadow="Never" style="height: 8vh" v-if="outputVisible">
      运行结果:{{ output }}
    </el-card>
    <el-dialog
        v-model="analysisCodeDialogVisible"
        title="Ai分析结果"
        width="650"
    >
      <span v-html="aiAnswer"></span>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="showAnalysisCodeDialog" class="confirm-btn">知道了</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import axios from 'axios';
import {getCurrentInstance, nextTick, onMounted, ref} from 'vue';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.main.js';
import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
import hljs from "highlight.js";
import 'highlight.js/styles/docco.css'
import {fetchEventSource} from "@microsoft/fetch-event-source";
// Ai分析弹窗是否显示
let analysisCodeDialogVisible = ref();
let aiAnswer = ref('');
let controller = new AbortController();
let signal = controller.signal;
let interval = null;
self.MonacoEnvironment = {
  getWorker() {
    return new JsonWorker();
  },
};

export default {
  props: {
    value: String,
  },
  setup(props, {emit})
  {
    const selectedLanguage = ref('C++');
    const showInput = ref(false);
    const inputContent = ref('');
    let monacoEditor = null;
    const output = ref('');
    const outputVisible = ref(false);
    const {proxy} = getCurrentInstance();

    onMounted(async () => {
      await nextTick();
      const lg=selectedLanguage.value==='C++'?'cpp':selectedLanguage.value;
      monacoEditor = monaco.editor.create(proxy.$refs.editContainer, {
        value: props.value || '',
        readOnly: false,
        language: lg,
        theme: 'vs',
        selectOnLineNumbers: true,
        renderSideBySide: false,
      });

      monacoEditor.onDidChangeModelContent(() => {
        const currentValue = monacoEditor?.getValue();
        emit('update:value', currentValue);
      });
    });

    const toggleInput = () => {
      showInput.value = !showInput.value;
    };

    function dealAnswer(data,answer) {
      let sseData = data;
      sseData = sseData.replaceAll("&#32;", " ").replaceAll("&#92n", "\n")
      // 当机器人回答时 设置ai回答状态为加载完成
      nextTick(() => {
        // Loading should be closed asynchronously
        loading.value.close()
      })
      answer += sseData;
      return answer;
    }

    // 将md转化为html
    function mdToHtml(content,callback) {
      import('markdown-it').then(module => {
        const md = module.default('commonmark', {
          highlight: function (str, lang) {
            if (lang && hljs.getLanguage(lang)) {
              try {
                return '<pre class="hljs"><code>' +
                    hljs.highlight(lang, str, true).value +
                    '</code></pre>';
              } catch (__) {}
            }

            return '<pre class="hljs"><code>' + md.utils.escapeHtml(str) + '</code></pre>';
          }
        });
        callback(md.render(content));
      });
    }

    const aiAnalysisCode = () => {
      aiAnswer.value = '';
      analysisCodeDialogVisible.value = true;
      console.log(monacoEditor.getValue())
      // fetch请求方法控制器
      let answer = '';
      let nowHtml = '';
      interval = setInterval(async () => {
        if ( nowHtml.length > aiAnswer.value.length ) {
          let nowLen = aiAnswer.value.length;
          if ( nowHtml[nowLen] === '<' ) {
            while ( nowHtml[nowLen] !== '>' ) {
              nowLen ++;
            }
          }
          aiAnswer.value = nowHtml.slice(0,nowLen+1);
        }
      },70)
      controller = new AbortController()
      signal = controller.signal;
      fetchEventSource("/api/aiChat/analysisCode", {
        method: 'POST',
        headers: {
          'content-type': 'application/json',
          'token': localStorage.getItem("token")
        },
        body: JSON.stringify({
          code: monacoEditor.getValue(),
          language: selectedLanguage.value,
          oiString: showInput.value ? inputContent.value : ""
        }),
        signal: signal,
        openWhenHidden: true,
        onmessage(event) {
          answer = dealAnswer(event.data,answer)
          if ( event.data === '&#92n[DONE]') {
            controller.abort();
            return;
          }
          mdToHtml(answer,(html)=>{
            nowHtml = html;
          })
        },
        onclose(event) {
          controller.abort();
        },
        onerror(event) {
          console.log('wrong');
          controller.abort();
        }
      });
    }

    const showAnalysisCodeDialog = () => {
      analysisCodeDialogVisible.value = false;
      controller.abort()
      clearInterval(interval)
    }



    const executeCode = async () => {
      const language = selectedLanguage.value === "cpp" ? "C++" : selectedLanguage.value;
      const codeData = {
        code: monacoEditor.getValue(),
        language: language,
        oiString: showInput.value ? inputContent.value : ""
      };

      try {
        const response = await axios.post(`/oj/commit/oi`, codeData);
        console.log(response.data);
        const result = response.data.data.data[0];
        output.value = result && result.files ? result.files.stdout : '没有输出';
        outputVisible.value = true;
      } catch (error) {
        if (error.response && error.response.status === 401) {
          // 处理401错误
          alert('未授权的访问，请重新登录。');
          // 可以在这里添加重新登录或重新获取token的逻辑
        } else {
          // 处理其他错误
          console.error('请求错误', error);
          alert('执行错误，请检查网络或联系管理员。');
        }
      }
    };


    return {
      output,
      outputVisible,
      selectedLanguage,
      showInput,
      inputContent,
      analysisCodeDialogVisible,
      aiAnswer,
      options: [
        {label: "C++", value: 'C++'},
        {label: 'JavaScript', value: 'javascript'},
        {label: 'Python3', value: 'Python3'},
        {label: 'Java', value: 'java'}
      ],
      updateLanguage: () => {
        monaco.editor.setModelLanguage(monacoEditor.getModel(), selectedLanguage.value);
      },
      toggleInput,
      executeCode,
      aiAnalysisCode,
      showAnalysisCodeDialog
    };
  }
,
};
</script>


<style scoped>
.layout-container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.header-container {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}

.select {
  width: 100px;
}

.code-editor {
  width: 100%;
  height: 55vh;
}

.button-container {
  display: flex;
  justify-content: space-between;
}

.button-icon {
  height: 2.2vh;
  margin-right: 5px;
}

.card {
  width: 100%;
  height: 88vh;
  margin-top: 2.5vh;
}

.input-box {
  width: 200px;
}

.dialog-footer {
  .confirm-btn {
    border: none !important;
    height: 32px;
    padding: 4px 16px;
    font-size: 14px;
    border-radius: 32px;
  }
}
</style>
